<?php

namespace Soen\Container\Aop;

use App\Command\HttpServerCommand;
use http\Exception\RuntimeException;
use PhpParser\Builder\Property;
use PhpParser\NodeVisitorAbstract;
use PhpParser\Node;
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Name;
use PhpParser\Node\Param;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Return_;
use PhpParser\Node\Stmt\TraitUse;
use PhpParser\NodeFinder;
use Node\Scalar\LNumber;

class ProxyVisitor extends NodeVisitorAbstract
{
	protected $className;

	protected $proxyId;

	protected $settings;

	public function __construct($className, $proxyId, array $setting = [])
	{
		$this->className = $className;
		$this->proxyId = $proxyId;
		$this->settings = $setting;
	}

	public function getProxyClassName(): string
	{
		return \basename(str_replace('\\', '/', $this->className)) . '_' . $this->proxyId;
//		return \basename($this->className) . '_' . $this->proxyId;
	}

	public function getClassName()
	{
		return '\\' . $this->className . '_' . $this->proxyId;
	}

    /**
     * 非数组 属性 节点 赋值
     * @param $item
     * @return Node\Scalar\LNumber|String_
     */
	public function createNodeByType($item){
        switch (gettype($item)) {
            case 'string':
                return new String_($item);
            case 'integer':
                return new Node\Scalar\LNumber($item);
        }
    }

    /**
     * 解析 属性 class
     * @param $class
     * @param $name
     * @return Node\Expr\ClassConstFetch
     */
    public function createClassConstFetch($class, $name){
        $className = new Name('\\' . $class);
	    return new Node\Expr\ClassConstFetch($className, $name);
    }

    public function createNodeArrayMultiple ($propertyArray, &$array_ = null) {
	    if (!$array_) {
            $array_ = new Node\Expr\Array_();
        }
	    foreach ($propertyArray as $key => $value){
            $nodeKey = null;
            $nodeVal = null;
	        if(is_string($key)){
                $nodeKey = new String_($key);
            }
            if(!is_array($value)){
                if($key === 'class'){
                    $nodeVal = $this->createClassConstFetch($value, 'class');
                } else {
                    $nodeVal = $this->createNodeByType($value);
                }
                $array_->items[$key] = new Node\Expr\ArrayItem($nodeVal, $nodeKey);
            }
	        if(is_array($value)){
                $array_->items[$key] = new Node\Expr\ArrayItem(new Node\Expr\Array_(), $nodeKey);
                $this->createNodeArrayMultiple($value, $array_->items[$key]->value);
            }
        }
	    return $array_;
    }



	public function leaveNode(Node $node)
	{
        if ($node instanceof Class_) {
            // Create proxy class base on parent class
	        $subNodes = [
		        'flags' => $node->flags,
		        'stmts' => $node->stmts
	        ];
	        if ($node->extends !== null) {
	        	$extendsClass = implode('\\', $node->extends->parts);
		        $subNodes['extends'] = new Name('\\' . $extendsClass);
	        }
            return new Class_($this->getProxyClassName(), $subNodes);
        }
        if($node instanceof Node\Stmt\Property && !empty($this->settings['propertys'])){
            if(array_key_exists($name = $node->props[0]->name->name, $this->settings['propertys'])){
                if (is_array($this->settings['propertys'][$name])){
//                    if($name == 'handlers'){
                        // 如果是数组 则通过数组 处理操作
                        $nodeArray = $this->createNodeArrayMultiple($this->settings['propertys'][$name]);
                        $node->props[0]->default = $nodeArray;
//                    } else {
//                        $nodeArrayItem = [];
//                        foreach ($this->settings['propertys'][$name] as &$value){
//                            $nodeArrayItem[] = new Node\Expr\ArrayItem($this->createNodeByType($value));
//                        }
//                        $node->props[0]->default = new Node\Expr\Array_($nodeArrayItem);
//                    }

                } else if (is_string($this->settings['propertys'][$name])){
                    if (!$node->props[0]->default) {
                        $node->props[0]->default = $this->createNodeByType($this->settings['propertys'][$name]);
                    } else {
                        $node->props[0]->default->value = $this->settings['propertys'][$name];
                    }
//                    var_dump($node);
                }
            }
			return $node;
        }
	}
}
